// 版权归Go作者所有。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package ssa

// FuseIntegerComparations优化不等式，例如“1<=x&&x<5”，
// 可以优化为“unsigned（x-1）<4”。
// 
// 寻找如下分支结构：
// 
// p 
// /| \
// /| b 
// /|/\
// S0S1 
// 
// 这将被优化为：
// 
// p 
// \
// b 
// \
// s0 s1 
// 
// 其中b的组合控制值为“unsigned（x-1）<4”。zhi jian cdefg
func fuseIntegerComparisons(b *Block) bool {
	if len(b.Preds) != 1 {
		return false
	}
	p := b.Preds[0].Block()
	if b.Kind != BlockIf || p.Kind != BlockIf {
		return false
	}

	if p.Likely == BranchLikely && p.Succs[0].Block() != b {
		return false
	}
	if p.Likely == BranchUnlikely && p.Succs[1].Block() != b {
		return false
	}

	// 检查控制值是否组合成一个整数不等式，
	// 以后可以进一步优化。
	bc := b.Controls[0]
	pc := p.Controls[0]
	if !areMergeableInequalities(bc, pc) {
		return false
	}

	// 如果第一个（真）后继者匹配，那么我们有一个析取（| |）。
	// 如果第二个（假）后继者匹配，则我们有一个连词（&&）。
	for i, op := range [2]Op{OpOrB, OpAndB} {
		if p.Succs[i].Block() != b.Succs[i].Block() {
			continue
		}

		// TODO（mundaym）：我们是否也应该检查执行b的成本？
		// 目前我们可能会推测执行b，即使b包含很多指令。我们可以检查len（b.值）
		// 是否低于固定值。但是请记住，其他优化过程可能会显著降低成本，所以我们不应该过于保守。
		if !canSpeculativelyExecute(b) {
			return false
		}

		// 逻辑组合p和b的控制值。
		v := b.NewValue0(bc.Pos, op, bc.Type)
		v.AddArg(pc)
		v.AddArg(bc)

		// 将组合的控制值设置为b的控制值。
		b.SetControl(v)

		// 修改p，使其直接跳到b。
		p.removeEdge(i)
		p.Kind = BlockPlain
		p.Likely = BranchUnknown
		p.ResetControls()

		return true
	}

	// TODO:可以否定条件以合并控制。
	return false
}

// GetContintargindex返回第一个参数的索引，该参数是
// 常量整数，如果不存在此类参数，则返回-1。
func getConstIntArgIndex(v *Value) int {
	for i, a := range v.Args {
		switch a.Op {
		case OpConst8, OpConst16, OpConst32, OpConst64:
			return i
		}
	}
	return -1
}

// isSignedInequality报告op是否代表不平等<或≤ 
// 在签名域中。
func isSignedInequality(v *Value) bool {
	switch v.Op {
	case OpLess64, OpLess32, OpLess16, OpLess8,
		OpLeq64, OpLeq32, OpLeq16, OpLeq8:
		return true
	}
	return false
}

// isUnsignedInequality报告op是否代表不平等<或≤ 
// 在未签名的域中。
func isUnsignedInequality(v *Value) bool {
	switch v.Op {
	case OpLess64U, OpLess32U, OpLess16U, OpLess8U,
		OpLeq64U, OpLeq32U, OpLeq16U, OpLeq8U:
		return true
	}
	return false
}

func areMergeableInequalities(x, y *Value) bool {
	// 我们需要这两个不等式要么在有符号域中，要么在无符号域中。
	// TODO（mundaym）：当我们有一个Eq运算时，合并
	// 也会很好，可以转换成一个Leq/Leq。例如，在无符号
	// 域中，'x==0 | | 3<x'相当于'x<=0 | | 3<x'
	inequalityChecks := [...]func(*Value) bool{
		isSignedInequality,
		isUnsignedInequality,
	}
	for _, f := range inequalityChecks {
		if !f(x) || !f(y) {
			continue
		}

		// 检查这两个不等式是否与常数比较。
		xi := getConstIntArgIndex(x)
		if xi < 0 {
			return false
		}
		yi := getConstIntArgIndex(y)
		if yi < 0 {
			return false
		}

		// 检查不等式
		// 的非常量参数是否相同。
		return x.Args[xi^1] == y.Args[yi^1]
	}
	return false
}
